package org.yzz.auth.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.yzz.auth.annotation.RonghuaPermission;
import org.yzz.auth.domain.Permission;
import org.yzz.auth.mapper.PermissionMapper;
import org.yzz.auth.service.IPermissionScanService;
import org.yzz.base.enums.RequestTypeEnum;
import org.yzz.base.util.ClassUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * 此类写 权限的执行流程
 */

@Service
public class PermissionScanServiceImpl implements IPermissionScanService {
    @Value("${basepackge.base-pack}")
    private String pack;

    @Autowired
    private PermissionMapper permissionMapper;
    @Override
    public void scan() {
        System.out.println("已经进入 scan+pack:"+pack);
        permissionMapper.deleteAll();
        // 1.拿到所有的包
        List<Class> allClassName = ClassUtils.getAllClassName(pack);
        // 2.获取所有的Controller
        // 判断是否有自定义注解
        for (Class clazz : allClassName) {
            //获取类上是否有自定义注解
           // Annotation annotationClass = clazz.getAnnotation(RonghuaPermission.class);
            // 转成 RonghuaPermission 类型的类注解，便于拼接父权限
            RonghuaPermission annotationClass = (RonghuaPermission)clazz.getAnnotation(RonghuaPermission.class);

            if (Objects.isNull(annotationClass)) {
                continue;
            }
            //获取类上的RequestMapping
            RequestMapping annotationRequestMapping = (RequestMapping)clazz.getAnnotation(RequestMapping.class);
            String name = clazz.getSimpleName();
            String[] value = annotationRequestMapping.value();  // 拿到的数组里面保存的就是路径 path
            // 拼父权限
            Permission parent = new Permission();
            parent.setName(annotationClass.name());
            parent.setDescs(annotationClass.descs());
            parent.setSn(name);     // 父权限只有类名
            parent.setUrl(annotationRequestMapping.value()[0]);
            // 父类入库
            permissionMapper.insert(parent);

            // 不为空则继续向下执行，annotationClass 表示有自定义注解的类
            // 3．拿到类中有自定义注解的方法
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                //判断方法是否有自定义注解  annotationMethod 表示有自定义注解的方法
                RonghuaPermission annotationMethod = method.getAnnotation(RonghuaPermission.class);
                if (Objects.isNull(annotationMethod)) {
                    continue;
                }

                //封装对象，首先需要取值：name,descs,url,sn,parent
                // 取完值就拼子类的
                Permission permission = new Permission();
                permission.setName(annotationMethod.name());
                permission.setDescs(annotationMethod.descs());
                permission.setSn(name+":"+method.getName());
                permission.setUrl(parent.getUrl()+getMethodUrl(method));
                permission.setParent(parent);
//                System.out.println("name属性: "+annotationMethod.name());
//                System.out.println("descs : "+annotationMethod.descs());
                // url 来自于 类上的mapping +方法上的mapping 中的 url 所以需要在两个地方分别取值再拼接
//                System.out.println("url : "+annotationMethod.url());
                // 方法上的 Mapping 有 n 多个可能，所以就需要用到枚举类+自定义的 getMethodUrl，得到 url
//                String methodUrl = getMethodUrl(method);

                //入库
                permissionMapper.insert(permission);
            }
        }
    }
    // 获取方法上的 Mapping 路径
    public String getMethodUrl(Method method){
        String methodUrl = "";
        // 取枚举中定义的所有的请求类型
        RequestTypeEnum[] requestTypeEnums = RequestTypeEnum.values();
        for (RequestTypeEnum typeEnum : requestTypeEnums) {
            // 根据枚举中的不同的请求类型的class获取该类型对应的注解对象
            Annotation annotation = method.getAnnotation(typeEnum.getRequestType());
            // 如果该请求类型注解不存在就跳过
            if(Objects.isNull(annotation)){
                continue;
            }
            try {
                // 如果该请求类型注解存在,就获取它里面的value方法
                Class<? extends Annotation> aClass = annotation.annotationType();
                Method annotationMethod = aClass.getMethod("value");
                // 通过invoke调用该对象的value方法,获取结果
                // 反射执行 方法 方法名.invoke(对象)
                String[] value = (String[]) annotationMethod.invoke(annotation);
                // 如果value不为空且长度大于0,就赋值给methodUrl,并跳出循环
                if(value != null && value.length > 0){
                    methodUrl = value[0];
                    break;
                }
            }catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }
        return methodUrl;
    }
}